iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 30
0
AI & Data

用Node.js製作後台零負擔的DiscordBot系列 第 30

Day30 - tag控管機制(4)

  • 分享至 

  • xImage
  •  

以下文章已於 2021/09/16 轉移至 微笑之家
對於discord.js更新,或是有其他問題,都歡迎到以下網址查看喔
本站
本主題
本文章


今天把tag的最後一件事做完

將使用者從指定權限組移除
將指定權限組移除

在tag入口新增Delete方法

30-1

創建實例

30-2

//從權限組中刪除使用者 OR 刪除權限組
function DeleteTag(msg) {
    try {
        if (DoUserID === '') {
            tempIsAdmin = CheckID(msg, null, msg.author.id, function(msg, cmd, haveUserData) {
                if (haveUserData.IsAdmin) return true;
                else return false;
            });
            if (tempIsAdmin) {
                nowDoFunction = DeleteTagNow;
                DoUserID = msg.author.id;
                DoData = new Array;
                msg.channel.send('請問要編輯使用者權限還是權限組?\n1 使用者權限 / 2 權限組');
            } else {
                msg.channel.send('此指令只有管理員可執行');
            }
        } else {
            msg.channel.send('有其他人正在使用續行中,請稍等');
        }
    } catch (err) {
        console.log('DeleteTagError', err);
    }
}

創建續行實例

//從權限組中刪除使用者 OR 刪除權限組(續行)
function DeleteTagNow(msg) {
    try {
        switch (DoingCount) {
            case 0:
                switch (msg.content) {
                    case '1':
                        msg.channel.send('請輸入要編輯的使用者ID');
                        break;
                    case '2':
                        DoingCount = 10;
                        msg.channel.send('請輸入要編輯的權限組');
                        break;
                    default:
                        DoingCount--;
                        msg.channel.send('無法辨識訊息,請輸入1/2來選擇');
                        break;
                }
                break;
            case 1:
                if (msg.content == 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('指令關閉');
                } else {
                    if (CheckID(msg, null, msg.content, (msg, cmd, haveUserData) => { return haveUserData })) {
                        DoData.push(msg.content); //userID
                        DoData.push(msg.author.id); //userName
                        msg.channel.send('請輸入要刪除的群組權限');
                    } else {
                        DoingCount--;
                        msg.channel.send('此用戶不存在資料,請確認,如果要關閉指令請輸入 N');
                    }
                }
                break;
            case 2:
                DoData.push(msg.content); // Power
                DoData.push(false); // IsAdmin
                msg.channel.send(`申請資料如下:\n申請人 <@${msg.author.id}>\n使用者 <@${DoData[0]}>\n刪除權限組 ${DoData[2]}\n正確 Y / 錯誤 N`);
                break;
            case 3:
                if (msg.content === 'Y') {
                    msg.channel.send('已確認,輸入資料中...');
                    //與舊資料比對,已有此人資料變進行更新
                    CheckID(msg, null, DoData[0], DeleteOldUserPower);
                    GetGas.postUserPower(DoData, function(dataED) {
                        if (dataED) {
                            //bot內變數不會更新,手動更新
                            UserPowerData.unshift({
                                'userID': DoData[0],
                                'userName': DoData[1],
                                'Joins': DoData[2],
                                'IsAdmin': DoData[3]
                            });
                            msg.channel.send('輸入完畢!');
                        } else {
                            msg.channel.send('資料輸入失敗,請重新嘗試');
                        }
                        CloseAllDoingFunction();
                    });
                } else if (msg.content === 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('已取消行為,請重新下達指令')
                } else {
                    DoingCount--;
                    msg.channel.send('無法辨識訊息,請輸入Y/N來選擇');
                }
                break;
            case 11:
                DoData.push(msg.content); //身分組ID
                DoData.push('2'); //type 2
                DoData.push('');
                msg.channel.send(`申請資料如下:\n申請人 <@${msg.author.id}>\n刪除權限組 ${DoData[0]}\n正確 Y / 錯誤 N`);
                break;
            case 12:
                if (msg.content === 'Y') {
                    msg.channel.send('已確認,輸入資料中...');
                    //與舊資料比對,沒有此身分組資料清除
                    DeleteOldPartyPower();
                    if (DoData[0] != '') {
                        GetGas.postPartyPower(DoData, function(dataED) {
                            if (dataED) {
                                //bot內變數不會更新,手動更新
                                PartyPowerData.unshift({
                                    'ID': DoData[0],
                                    'type': DoData[1],
                                    'Power': DoData[2]
                                });
                                msg.channel.send('輸入完畢!');
                            } else {
                                msg.channel.send('資料輸入失敗,請重新嘗試');
                            }
                            CloseAllDoingFunction();
                        });
                    } else {
                        msg.channel.send('輸入完畢!');
                        CloseAllDoingFunction();
                    }
                } else if (msg.content === 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('已取消行為,請重新下達指令')
                } else {
                    DoingCount--;
                    msg.channel.send('無法辨識訊息,請輸入Y/N來選擇');
                }
                break;
        }
        if (DoUserID !== '') DoingCount++;
    } catch (err) {
        CloseAllDoingFunction();
        client.channels.fetch(msg.channel.id).then(channel => channel.send('發生意外錯誤,中斷指令行為,請重新下達指令!'))
        console.log('DeleteTagNowError', err);
    }
}

創建刪除類方法

30-3

//用戶舊資料更新
function DeleteOldUserPower(msg, cmd, haveUserData) {
    //二次確認
    if (haveUserData) {
        if (DoData[0] == haveUserData.userID) {
            let str = haveUserData.Joins;
            DoData[2] = str.toString().replace(DoData[2], '');
            DoData[3] = haveUserData.IsAdmin;
            return true;
        } else return false;
    } else return false;
}

30-4

//權限組舊資料更新
function DeleteOldPartyPower() {
    if (PartyPowerData) {
        const tempPartyData = PartyPowerData.find(element => {
            return element.ID == DoData[0];
        })

        if (tempPartyData == undefined) {
            DoData[0] = '';
            DoData[1] = '';
            DoData[2] = '';
        }
    }
}

運行看看

30-5

30-6

30-7

30-8

成功

到此,番外的部分也說完了

與基本的內容不同,多說了post的API,以及程式碼的部份相對複雜
且比起前面的篇幅,後續的文章大多都是直接貼了程式碼的順序,很少講解

想必讀起來十分艱澀吧?能讀到這裡的你是十分了不起的,恭喜你看完了這篇文章

儘管如此,這支程式仍然是不成熟的,筆者對每個功能盡量都只是點到為止,希望能把大部份的應用都帶到,後面便是要靠各位讀者
根據自己遇到的需求,來改善加強他吧,相信只要努力堅持,完成後的機器人一定會帶給各位程式能力上的提升的

那麼,用Node.js製作後台零負擔的DiscordBot到此結束
祝各位中秋佳節愉快

底下附上完整的bot.js,供參考

//#region 全域變數
const Discord = require('discord.js');
const client = new Discord.Client();
const ytdl = require('ytdl-core');
const ytpl = require('ytpl');
const auth = require('./JSONHome/auth.json');
const prefix = require('./JSONHome/prefix.json');
const GetGas = require('./Script/GetGas.js');
const shup = require('./JSONHome/shup.json');

//存放BaseExcelAPI資料
let BaseExcelData = false;
let UserPowerData = false;
let PartyPowerData = false;

//持續執行方法
let nowDoFunction = false;
let DoingCount = 0;
let DoUserID = '';
let DoData = undefined;

//#endregion

//#region 登入
client.login(auth.key);

client.on('ready', () => {
    GetGas.getBaseExcel(function(dataED) {
        if (dataED) {
            BaseExcelData = dataED //有資料
        }
        GetGas.getUserPower(function(dataED) {
            if (dataED) {
                UserPowerData = dataED;
            }
            GetGas.getPartyPower(function(dataED) {
                if (dataED) {
                    PartyPowerData = dataED;
                }
                console.log(`Logged in as ${client.user.tag}!`);
            });
        })
    })
});

//#endregion

//#region message事件入口
client.on('message', msg => {
    //前置判斷
    try {
        if (!msg.guild || !msg.member) return; //訊息內不存在guild元素 = 非群組消息(私聊)
        if (!msg.member.user) return; //幫bot值多拉一層,判斷上層物件是否存在
        if (msg.member.user.bot) return; //訊息內bot值為正 = 此消息為bot發送
    } catch (err) {
        return;
    }

    //續行方法
    if (nowDoFunction && msg.author.id === DoUserID) {
        nowDoFunction(msg);
        return;
    }

    //字串分析
    try {
        let tempPrefix = '-1';
        const prefixED = Object.keys(prefix); //前綴符號定義
        prefixED.forEach(element => {
            if (msg.content.substring(0, prefix[element].Value.length) === prefix[element].Value) {
                tempPrefix = element;
            }
        });

        //禁言系統判斷
        if (!IsShut(msg, tempPrefix)) return;

        //實作
        switch (tempPrefix) {
            case '0': //文字回應功能
                BasicFunction(msg, tempPrefix);
                break;
            case '1': //音樂指令 
                MusicFunction(msg);
                break;
            case '2': //機器人tag指令
                TagFunction(msg, tempPrefix);
                break;
            default:
                BaseExcelFunction(msg);
                break;
        }
    } catch (err) {
        console.log('OnMessageError', err);
    }
});

//#endregion

//#region 基本指令系統
function BasicFunction(msg, tempPrefix) {
    const cmd = msg.content.substring(prefix[tempPrefix].Value.length).split(' '); //以空白分割前綴以後的字串
    switch (cmd[0]) {
        case 'ping':
            msg.channel.send('pong');
            break;
        case '老婆':
            msg.reply('你沒有老婆!!');
            break;
        case 'myAvatar':
            const avatar = GetMyAvatar(msg);
            if (avatar.files) msg.channel.send(`${msg.author}`, avatar).catch(err => { console.log(err) });
            break;
            // case 'test':
            //     const testStr2 = msg.content.split(' ');
            //     console.log(client.users.fetch(testStr2[1]).then(element => console.log(element.displayAvatarURL())));
            //     break;
    }
}

//#endregion

//#region 音樂系統
//歌曲控制器
let dispatcher = new Map();
//歌曲清單
let musicList = new Map();

function MusicFunction(msg) {
    //將訊息內的前綴字截斷,後面的字是我們要的
    const content = msg.content.substring(prefix[1].Value.length);
    //指定我們的間隔符號
    const splitText = ' ';
    //用間隔符號隔開訊息 contents[0] = 指令,contents[1] = 參數
    const contents = content.split(splitText);
    //因為會持續使用到,將群組ID獨立成參數
    const guildID = msg.guild.id;

    switch (contents[0]) {
        case 'play':
            //點歌&播放歌曲功能
            playMusic(guildID, msg, contents);
            break;
        case 'replay':
            //重播當前歌曲
            replayMusic(guildID);
            break;
        case 'np':
            //當前歌曲資訊
            nowPlayMusic(guildID, msg.channel.id);
            break;
        case 'queue':
            //歌曲清單
            queueShow(guildID, msg.channel.id);
            break;
        case 'skip':
            //中斷歌曲
            skipMusic(guildID);
            break;
        case 'disconnect':
            //退出語音頻道並且清空歌曲清單
            disconnectMusic(guildID, msg.channel.id);
            break;
        case 'playList':
            //載入歌單
            playListMusic(guildID, msg);
            break;
    }
}

//?play
async function playMusic(guildID, msg, contents) {
    //定義我們的第一個參數必需是網址
    const urlED = contents[1];
    try {
        //第一個參數不是連結就要篩選掉
        if (urlED.substring(0, 4) !== 'http') return msg.reply('The link is not working.1');

        //透過library判斷連結是否可運行
        const validate = await ytdl.validateURL(urlED);
        if (!validate) return msg.reply('The link is not working.2');

        //獲取歌曲資訊
        const info = await ytdl.getInfo(urlED);
        //判斷資訊是否正常
        if (info.videoDetails) {
            //指令下達者是否在語音頻道
            if (msg.member.voice.channel) {
                //判斷bot是否已經連到語音頻道 是:將歌曲加入歌單 不是:進入語音頻道並且播放歌曲
                if (!client.voice.connections.get(msg.guild.id)) {
                    //因為是第一次加入,宣告新的歌曲列表
                    musicList.set(guildID, new Array());

                    //將歌曲加入歌單
                    musicList.get(guildID).push(urlED);
                    //進入語音頻道
                    msg.member.voice.channel.join()
                        .then(connection => {
                            msg.reply('來了~');
                            //const guildID = msg.guild.id;
                            const channelID = msg.channel.id;
                            //播放歌曲
                            playMusic2(connection, guildID, channelID);
                        })
                        .catch(err => {
                            msg.reply('bot進入語音頻道時發生錯誤,請再試一次');
                            console.log(err, 'playMusicError2');
                        })
                } else {
                    //將歌曲加入歌單
                    musicList.get(guildID).push(urlED);
                    msg.reply('已將歌曲加入歌單!');
                }
            } else return msg.reply('請先進入頻道:3...');
        } else return msg.reply('The link is not working.3');
    } catch (err) {
        console.log(err, 'playMusicError');
    }
}

//?play 遞迴函式
async function playMusic2(connection, guildID, channelID) {
    try {
        //播放前歌曲清單不能沒有網址
        if (musicList.get(guildID).length > 0) {
            //設定音樂相關參數
            const streamOptions = {
                seek: 0,
                volume: 0.5,
                Bitrate: 192000,
                Passes: 1,
                highWaterMark: 1
            };
            //讀取清單第一位網址
            const stream = await ytdl(musicList.get(guildID)[0], {
                filter: 'audioonly',
                quality: 'highestaudio',
                highWaterMark: 26214400 //25ms
            })

            //播放歌曲,並且存入dispatcher
            dispatcher.set(guildID, connection.play(stream, streamOptions));
            //監聽歌曲播放結束事件
            dispatcher.get(guildID).on("finish", finish => {
                //將清單中第一首歌清除
                if (musicList.get(guildID).length > 0) musicList.get(guildID).shift();
                //播放歌曲
                playMusic2(connection, guildID, channelID);
            })
        } else disconnectMusic(guildID, channelID); //清空歌單並且退出語音頻道
    } catch (err) {
        console.log(err, 'playMusic2Error');
    }
}

//?disconnect
function disconnectMusic(guildID, channelID) {
    try {
        //判斷bot是否在此群組的語音頻道
        if (client.voice.connections.get(guildID)) {
            //清空歌曲清單
            musicList.set(guildID, new Array());
            //退出語音頻道
            client.voice.connections.get(guildID).disconnect();

            client.channels.fetch(channelID).then(channel => channel.send('晚安~'));
        } else client.channels.fetch(channelID).then(channel => channel.send('可是..我還沒進來:3'))
    } catch (err) {
        console.log(err, 'disconnectMusicError');
    }
}

//?replay
function replayMusic(guildID) {
    if (musicList.get(guildID).length > 0) {
        //把當前曲目再推一個到最前面
        musicList.get(guildID).unshift(musicList[0]);
        //將歌曲關閉,觸發finish事件
        //finish事件將清單第一首歌排出,然後繼續播放下一首
        if (dispatcher.get(guildID) !== undefined) dispatcher.get(guildID).end();
    }
}

//?skip
function skipMusic(guildID) {
    //將歌曲關閉,觸發finish事件
    if (dispatcher.get(guildID) !== undefined) dispatcher.get(guildID).end();
}

//?np
async function nowPlayMusic(guildID, channelID) {
    try {
        if (dispatcher.get(guildID) !== undefined && musicList.get(guildID).length > 0) {
            //從連結中獲取歌曲資訊 標題 總長度等
            const info = await ytdl.getInfo(musicList.get(guildID)[0]);
            //歌曲標題
            const title = info.videoDetails.title;
            //歌曲全長(s)
            const songLength = info.videoDetails.lengthSeconds;
            //當前播放時間(ms)
            const nowSongLength = Math.floor(dispatcher.get(guildID).streamTime / 1000);
            //串字串
            const message = `${title}\n${streamString(songLength,nowSongLength)}`;
            client.channels.fetch(channelID).then(channel => channel.send(message))
        }
    } catch (err) {
        console.log(err, 'nowPlayMusicError');
    }
}

//▬▬▬▬▬▬▬▬▬?▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
function streamString(songLength, nowSongLength) {
    let mainText = '?';
    const secondText = '▬';
    const whereMain = Math.floor((nowSongLength / songLength) * 100);
    let message = '';
    for (i = 1; i <= 30; i++) {
        if (i * 3.3 + 1 >= whereMain) {
            message = message + mainText;
            mainText = secondText;
        } else {
            message = message + secondText;
        }
    }
    return message;
}

//?queue
async function queueShow(guildID, channelID) {
    try {
        if (musicList.get(guildID).length > 0) {
            let info;
            let message = '';
            for (i = 0; i < musicList.get(guildID).length; i++) {
                //從連結中獲取歌曲資訊 標題 總長度等
                info = await ytdl.getInfo(musicList.get(guildID)[i]);
                //歌曲標題
                title = info.videoDetails.title;
                //串字串
                message = message + `\n${i+1}. ${title}`;
            }
            //把最前面的\n拿掉
            message = message.substring(1, message.length);
            if (message.length > 1900) message = message.substring(0, 1900);
            client.channels.fetch(channelID).then(channel => channel.send(message))
        }
    } catch (err) {
        console.log(err, 'queueShowError');
    }
}

//?playList
async function playListMusic(guildID, msg) {
    try {
        //沒在音樂廳不能使用此功能
        if (!client.voice.connections.get(guildID)) {
            msg.channel.send(`請先正常啟用音樂指令後,再使用歌單載入喔`);
            return false;
        }
        //網址
        const valueED = msg.content.split(' ');
        //先用library自帶的方式檢查一次能不能用
        const canPlay = await ytpl.validateID(valueED[1]);
        //讀取到幾首歌,上限默認100首
        let a = 0;
        //幾首成功放入歌單
        let b = 0;
        if (canPlay) {
            const listED = await ytpl(valueED[1]);
            await listED.items.forEach(async function(element) {
                a = a + 1;
                if (element.title !== '[Deleted video]') {
                    canPlay2 = await ytdl.validateURL(element.url_simple);
                    if (canPlay2) {
                        b = b + 1;
                        musicList.get(guildID).push(element.url_simple);
                    }
                }
            });
            //回傳統計資訊
            msg.channel.send(`歌單 ${listED.title}\n共載入${b}首歌曲\n${a-b}首載入失敗`);
        } else {
            msg.channel.send(`This Url isn't working in function.`);
        }
    } catch (err) {
        console.log(err, 'playListMusicError');
    }
}
//#endregion

//#region tag系統
function TagFunction(msg, tempPrefix) {
    const cmd = msg.content.substring(prefix[tempPrefix].Value.length).split(' '); //以空白分割前綴以後的字串

    switch (cmd[0]) {
        case 'AddUser': //將使用者加入身份組
            addUserFunction(msg);
            break;
        case 'CreateParty': //創建身分組&增加身分組可tag對象
            CreatePartyFunction(msg);
            break;
        case 'Delete': //從權限組中刪除使用者 OR 刪除權限組
            DeleteTag(msg);
            break;
        default: //身份組ID
            tagOther(msg, cmd);
            break;
    }
}

//tag人
function tagOther(msg, cmd) {
    CheckID(msg, cmd, msg.author.id, (msg, cmd, haveUserData) => {
        CheckParty(msg, cmd, haveUserData, SendTagMessage);
    });
}

//判斷此人有沒有登記資料
function CheckID(msg, cmd, userID, OtherFunction) {
    const haveUserData = UserPowerData.find(element => {
        return element.userID == userID;
    })

    if (haveUserData !== undefined) {
        //有資料
        return OtherFunction(msg, cmd, haveUserData);
    } else {
        return OtherFunction(msg, cmd, false);
    }
}

//根據UserPower獲得Party
function CheckParty(msg, cmd, haveUserData, OtherFunction) {
    let havePartyPower;
    havePartyPower = PartyPowerData.filter(element => {
        if (haveUserData.Joins[i].indexOf(element.ID) != -1) {
            return element.Power.indexOf(cmd[1]) != -1
        }
    })

    if (isEmptyObject(havePartyPower)) {
        return OtherFunction(msg, cmd, haveUserData, false);
    } else {
        return OtherFunction(msg, cmd, haveUserData, havePartyPower);
    }
}

//傳送訊息單獨實例
function SendTagMessage(msg, cmd, haveUserData, havePartyPower) {
    if (haveUserData.IsAdmin) {
        msg.channel.send(`<@&${cmd[1]}>\n來自管理員<@${msg.author.id}>的指令呼叫`);
    } else if (havePartyPower) {
        msg.channel.send(`<@&${cmd[1]}>\n來自<@${msg.author.id}>的指令呼叫`);
    } else {
        msg.channel.send('無權限,請確認參數是否正確');
    }
}

//將xxx加入身分組
function addUserFunction(msg) {
    try {
        if (DoUserID === '') {
            tempIsAdmin = CheckID(msg, null, msg.author.id, function(msg, cmd, haveUserData) {
                if (haveUserData.IsAdmin) return true;
                else return false;
            });
            if (tempIsAdmin) {
                nowDoFunction = addUserFunctionNow;
                DoUserID = msg.author.id;
                DoData = new Array;
                msg.channel.send('請輸入要加入的使用者id');
            } else {
                msg.channel.send('此指令只有管理員可執行');
            }
        } else {
            msg.channel.send('有其他人正在使用續行中,請稍等');
        }
    } catch (err) {
        console.log('addUserFunctionError', err);
    }
}

//將xxx加入身份組(續行方法)
function addUserFunctionNow(msg) {
    try {
        switch (DoingCount) {
            case 0:
                DoData.push(msg.content); //加入使用者id
                DoData.push(msg.author.username); //加入申請者名字
                msg.channel.send(`請輸入要加入的群組`);
                break;
            case 1:
                DoData.push(msg.content); //加入群組
                DoData.push(false); //IsAdmin預設False不可修改
                msg.channel.send(`申請資料如下:\n申請人 <@${msg.author.id}>\n使用者 <@${DoData[0]}>\n加入權限組 ${DoData[2]}\n正確 Y / 錯誤 N`);
                break;
            case 2:
                if (msg.content === 'Y') {
                    msg.channel.send('已確認,輸入資料中...');
                    //與舊資料比對,已有此人資料變進行更新
                    CheckID(msg, null, DoData[0], EditOldUserPower);
                    GetGas.postUserPower(DoData, function(dataED) {
                        if (dataED) {
                            //bot內變數不會更新,手動更新
                            UserPowerData.unshift({
                                'userID': DoData[0],
                                'userName': DoData[1],
                                'Joins': DoData[2],
                                'IsAdmin': DoData[3]
                            });
                            msg.channel.send('輸入完畢!');
                        } else {
                            msg.channel.send('資料輸入失敗,請重新嘗試');
                        }
                        CloseAllDoingFunction();
                    });
                } else if (msg.content === 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('已取消行為,請重新下達指令')
                } else {
                    DoingCount--;
                    msg.channel.send('無法辨識訊息,請輸入Y/N來選擇');
                }
                break;
        }
        if (DoUserID !== '') DoingCount++;
    } catch (err) {
        CloseAllDoingFunction();
        client.channels.fetch(msg.channel.id).then(channel => channel.send('發生意外錯誤,中斷指令行為,請重新下達指令!'))
        console.log('addUserFunctionNowError', err);
    }
}

//用戶舊資料更新
function EditOldUserPower(msg, cmd, haveUserData) {
    //二次確認
    if (haveUserData) {
        if (DoData[0] == haveUserData.userID) {
            DoData[2] = haveUserData.Joins + ';' + DoData[2];
            DoData[3] = haveUserData.IsAdmin;
            return true;
        } else return false;
    } else return false;
}

//用戶舊資料更新
function DeleteOldUserPower(msg, cmd, haveUserData) {
    //二次確認
    if (haveUserData) {
        if (DoData[0] == haveUserData.userID) {
            let str = haveUserData.Joins;
            DoData[2] = str.toString().replace(DoData[2], '');
            DoData[3] = haveUserData.IsAdmin;
            return true;
        } else return false;
    } else return false;
}

//創建身分組&增加身分組可tag對象
function CreatePartyFunction(msg) {
    try {
        if (DoUserID === '') {
            tempIsAdmin = CheckID(msg, null, msg.author.id, function(msg, cmd, haveUserData) {
                if (haveUserData) {
                    if (haveUserData.IsAdmin) return true;
                    else return false;
                } else return false;
            });
            if (tempIsAdmin) {
                nowDoFunction = CreatePartyFunctionNow;
                DoUserID = msg.author.id;
                DoData = new Array;
                msg.channel.send('請輸入身份組名稱');
            } else {
                msg.channel.send('此指令只有管理員可執行');
            }
        } else {
            msg.channel.send('有其他人正在使用續行中,請稍等');
        }
    } catch (err) {
        console.log('CreatePartyFunctionError', err);
    }
}

//創建身分組&增加身分組可tag對象(續行)
function CreatePartyFunctionNow(msg) {
    try {
        switch (DoingCount) {
            case 0:
                DoData.push(msg.content); //身分組ID
                DoData.push('2'); //type 2
                msg.channel.send(`請輸入要加入的tagID`);
                break;
            case 1:
                DoData.push(msg.content); //加入tagID
                msg.channel.send(`申請資料如下:\n申請人 <@${msg.author.id}>\n權限組 ${DoData[0]}\ntagID ${DoData[2]}\n正確 Y / 錯誤 N`);
                break;
            case 2:
                if (msg.content === 'Y') {
                    msg.channel.send('已確認,輸入資料中...');
                    //與舊資料比對,已有此人資料變進行更新
                    EditOldPartyPower();
                    GetGas.postPartyPower(DoData, function(dataED) {
                        if (dataED) {
                            //bot內變數不會更新,手動更新
                            PartyPowerData.unshift({
                                'ID': DoData[0],
                                'type': DoData[1],
                                'Power': DoData[2]
                            });
                            msg.channel.send('輸入完畢!');
                        } else {
                            msg.channel.send('資料輸入失敗,請重新嘗試');
                        }
                        CloseAllDoingFunction();
                    });
                } else if (msg.content === 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('已取消行為,請重新下達指令')
                } else {
                    DoingCount--;
                    msg.channel.send('無法辨識訊息,請輸入Y/N來選擇');
                }
                break;
        }
        if (DoUserID !== '') DoingCount++;
    } catch (err) {
        CloseAllDoingFunction();
        client.channels.fetch(msg.channel.id).then(channel => channel.send('發生意外錯誤,中斷指令行為,請重新下達指令!'))
        console.log('CreatePartyFunctionNowError', err);
    }
}

//權限組舊資料更新
function EditOldPartyPower() {
    if (PartyPowerData) {
        const tempPartyData = PartyPowerData.find(element => {
            return element.ID == DoData[0];
        })

        if (tempPartyData !== undefined) {
            DoData[2] = tempPartyData.Power + ';' + DoData[2];
        }
    }
}

//權限組舊資料更新
function DeleteOldPartyPower() {
    if (PartyPowerData) {
        const tempPartyData = PartyPowerData.find(element => {
            return element.ID == DoData[0];
        })

        if (tempPartyData == undefined) {
            DoData[0] = '';
            DoData[1] = '';
            DoData[2] = '';
        }
    }
}

//從權限組中刪除使用者 OR 刪除權限組
function DeleteTag(msg) {
    try {
        if (DoUserID === '') {
            tempIsAdmin = CheckID(msg, null, msg.author.id, function(msg, cmd, haveUserData) {
                if (haveUserData.IsAdmin) return true;
                else return false;
            });
            if (tempIsAdmin) {
                nowDoFunction = DeleteTagNow;
                DoUserID = msg.author.id;
                DoData = new Array;
                msg.channel.send('請問要編輯使用者權限還是權限組?\n1 使用者權限 / 2 權限組');
            } else {
                msg.channel.send('此指令只有管理員可執行');
            }
        } else {
            msg.channel.send('有其他人正在使用續行中,請稍等');
        }
    } catch (err) {
        console.log('DeleteTagError', err);
    }
}

//從權限組中刪除使用者 OR 刪除權限組(續行)
function DeleteTagNow(msg) {
    try {
        switch (DoingCount) {
            case 0:
                switch (msg.content) {
                    case '1':
                        msg.channel.send('請輸入要編輯的使用者ID');
                        break;
                    case '2':
                        DoingCount = 10;
                        msg.channel.send('請輸入要編輯的權限組');
                        break;
                    default:
                        DoingCount--;
                        msg.channel.send('無法辨識訊息,請輸入1/2來選擇');
                        break;
                }
                break;
            case 1:
                if (msg.content == 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('指令關閉');
                } else {
                    if (CheckID(msg, null, msg.content, (msg, cmd, haveUserData) => { return haveUserData })) {
                        DoData.push(msg.content); //userID
                        DoData.push(msg.author.id); //userName
                        msg.channel.send('請輸入要刪除的群組權限');
                    } else {
                        DoingCount--;
                        msg.channel.send('此用戶不存在資料,請確認,如果要關閉指令請輸入 N');
                    }
                }
                break;
            case 2:
                DoData.push(msg.content); // Power
                DoData.push(false); // IsAdmin
                msg.channel.send(`申請資料如下:\n申請人 <@${msg.author.id}>\n使用者 <@${DoData[0]}>\n刪除權限組 ${DoData[2]}\n正確 Y / 錯誤 N`);
                break;
            case 3:
                if (msg.content === 'Y') {
                    msg.channel.send('已確認,輸入資料中...');
                    //與舊資料比對,已有此人資料變進行更新
                    CheckID(msg, null, DoData[0], DeleteOldUserPower);
                    GetGas.postUserPower(DoData, function(dataED) {
                        if (dataED) {
                            //bot內變數不會更新,手動更新
                            UserPowerData.unshift({
                                'userID': DoData[0],
                                'userName': DoData[1],
                                'Joins': DoData[2],
                                'IsAdmin': DoData[3]
                            });
                            msg.channel.send('輸入完畢!');
                        } else {
                            msg.channel.send('資料輸入失敗,請重新嘗試');
                        }
                        CloseAllDoingFunction();
                    });
                } else if (msg.content === 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('已取消行為,請重新下達指令')
                } else {
                    DoingCount--;
                    msg.channel.send('無法辨識訊息,請輸入Y/N來選擇');
                }
                break;
            case 11:
                DoData.push(msg.content); //身分組ID
                DoData.push('2'); //type 2
                DoData.push('');
                msg.channel.send(`申請資料如下:\n申請人 <@${msg.author.id}>\n刪除權限組 ${DoData[0]}\n正確 Y / 錯誤 N`);
                break;
            case 12:
                if (msg.content === 'Y') {
                    msg.channel.send('已確認,輸入資料中...');
                    //與舊資料比對,沒有此身分組資料清除
                    DeleteOldPartyPower();
                    if (DoData[0] != '') {
                        GetGas.postPartyPower(DoData, function(dataED) {
                            if (dataED) {
                                //bot內變數不會更新,手動更新
                                PartyPowerData.unshift({
                                    'ID': DoData[0],
                                    'type': DoData[1],
                                    'Power': DoData[2]
                                });
                                msg.channel.send('輸入完畢!');
                            } else {
                                msg.channel.send('資料輸入失敗,請重新嘗試');
                            }
                            CloseAllDoingFunction();
                        });
                    } else {
                        msg.channel.send('輸入完畢!');
                        CloseAllDoingFunction();
                    }
                } else if (msg.content === 'N') {
                    CloseAllDoingFunction();
                    msg.channel.send('已取消行為,請重新下達指令')
                } else {
                    DoingCount--;
                    msg.channel.send('無法辨識訊息,請輸入Y/N來選擇');
                }
                break;
        }
        if (DoUserID !== '') DoingCount++;
    } catch (err) {
        CloseAllDoingFunction();
        client.channels.fetch(msg.channel.id).then(channel => channel.send('發生意外錯誤,中斷指令行為,請重新下達指令!'))
        console.log('DeleteTagNowError', err);
    }
}

//#endregion

//#region 對話資料庫系統
function BaseExcelFunction(msg) {
    const messageED = GetBaseExcelData(msg);
    if (messageED) msg.channel.send(messageED);
}

//#endregion

//#region 子類方法
//獲取頭像
function GetMyAvatar(msg) {
    try {
        return {
            files: [{
                attachment: msg.users.author.displayAvatarURL('png', true),
                name: 'avatar.jpg'
            }]
        };
    } catch (err) {
        console.log('GetMyAvatar,Error');
    }
}

//BaseExcel字串比對
function GetBaseExcelData(msg) {
    try {
        if (BaseExcelData) {
            const userMessage = msg.content;

            e = BaseExcelData.filter(element => {
                return element.NAME === userMessage;
            })

            if (e.length != 0) return e[0].VALUE;
            else return false;
        }
    } catch (err) {
        console.log('GetBaseExcelDataError', err);
    }
}

//禁言系統判斷
function IsShut(msg, tempPrefix) {
    //群組id
    const guildID = msg.guild.id;
    //頻道id
    const channelID = msg.channel.id;
    //當前狀態
    let status = true;

    //先判斷群組,群組判斷完判斷頻道(頻道權限優先於群組)
    const guildIF = shup.Group.find(element => {
        if (element.GroupID == guildID) {
            return element.Power.indexOf(tempPrefix) !== -1;
        }
        return false;
    })

    //找到資料 = 此群組存在Group中且Power存在此次指令代碼
    if (guildIF !== undefined) {
        status = false;
    }

    //頻道
    const channelIF = shup.Channel.find(element => {
        if (element.ChannelID == channelID) {
            return true;
        }
        return false;
    })

    //找到資料 = 此頻道存在Channel中
    if (channelIF !== undefined) {
        //Power有此資料=>禁用功能 無資料=>不設限
        if (channelIF.Power.indexOf(tempPrefix) !== -1) {
            status = false;
        } else {
            status = true;
        }
    }

    return status;
}

//ArrayIsEmpty
function isEmptyObject(obj) {
    return !Object.keys(obj).length;
}

//關閉續行方法
function CloseAllDoingFunction() {
    nowDoFunction = false;
    DoingCount = 0;
    DoUserID = '';
    DoData = undefined;
}
//#endregion

上一篇
Day29 - tag控管機制(3)
下一篇
沉沉入睡的回憶小姐,匆匆揚帆的時間先生
系列文
用Node.js製作後台零負擔的DiscordBot31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Starrylemon
iT邦新手 5 級 ‧ 2021-02-02 22:52:09

我嘗試運行bot的時候出現這個诶:

Error: Cannot find module 'request'
Require stack:

  • C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js
  • C:\Users\88690\OneDrive\桌面\dctsb\bot.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:925:15)
    at Function.Module._load (node:internal/modules/cjs/loader:769:27)
    at Module.require (node:internal/modules/cjs/loader:997:19)
    at require (node:internal/modules/cjs/helpers:92:18)
    at Object. (C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js:3:17)
    at Module._compile (node:internal/modules/cjs/loader:1108:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
    at Module.load (node:internal/modules/cjs/loader:973:32)
    at Function.Module._load (node:internal/modules/cjs/loader:813:14)
    at Module.require (node:internal/modules/cjs/loader:997:19) {
    code: 'MODULE_NOT_FOUND',
    requireStack: [
    'C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js',
    'C:\Users\88690\OneDrive\桌面\dctsb\bot.js'
    ]
    }
看更多先前的回應...收起先前的回應...
微笑 iT邦研究生 5 級 ‧ 2021-02-03 09:08:32 檢舉

看起來是沒安裝request,試試在專案根目錄打開cmd,然後打以下
npm install request

可是我用完以後又出現這個了:

getBaseExcelError TypeError: callback is not a function
at Request._callback (C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js:44:17)
at Request.self.callback (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:185:22)
at Request.emit (node:events:379:20)
at Request. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1154:10)
at Request.emit (node:events:379:20)
at IncomingMessage. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1076:12)
at Object.onceWrapper (node:events:485:28)
at IncomingMessage.emit (node:events:391:22)
at endReadableNT (node:internal/streams/readable:1307:12)
at processTicksAndRejections (node:internal/process/task_queues:81:21)
C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js:48
callback('getBaseExcelError');
^

TypeError: callback is not a function
at Request._callback (C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js:48:13)
at Request.self.callback (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:185:22)
at Request.emit (node:events:379:20)
at Request. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1154:10)
at Request.emit (node:events:379:20)
at IncomingMessage. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1076:12)
at Object.onceWrapper (node:events:485:28)
at IncomingMessage.emit (node:events:391:22)
at endReadableNT (node:internal/streams/readable:1307:12)
at processTicksAndRejections (node:internal/process/task_queues:81:21)

微笑 iT邦研究生 5 級 ‧ 2021-02-03 16:54:15 檢舉

他說你的GetGas.js檔,第48行呼叫了callback,但是他不是一個方法

你要檢查的地方有兩點

  1. GetGas.js第48行,使用callback的那個function,參數是否有callback
  2. 在bot.js調用此方法時,對應callback的傳參是否是function

因為我的範例第48行不是callback,估計你寫得不太一樣,不太懂得話可以把bot.js跟GetGas.js傳上來給我看看

微笑 iT邦研究生 5 級 ‧ 2021-02-04 09:33:51 檢舉

看了一下,你在GetGas使用的getBaseExcel是Day19的
啟動時載入資料的功能是Day20寫的,getBaseExcel有做過修改
最重要的部分就是傳參從原本的userTalk, callback變成只有callback

這時bot.js在啟動時,執行了這串

GetGas.getBaseExcel(function(dataED) {
        if (dataED) {
            BaseExcelData = dataED //有資料
        }
        ...
        })

因為我們呼叫的時候只填入了一個方法,這個時候,回傳方法會是userTalk,而callback是undefind

總之把Day20的內容重看一次應該就沒問題了
Day19我故意用了比較糟糕的寫法,這部份導致誤會了,不好意思/images/emoticon/emoticon56.gif

可是我再次執行的時候出現了這個:

getBaseExcelError SyntaxError: Unexpected token < in JSON at position 1
at JSON.parse ()
at Request._callback (C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js:36:35)
at Request.self.callback (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:185:22)
at Request.emit (node:events:379:20)
at Request. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1154:10)
at Request.emit (node:events:379:20)
at IncomingMessage. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1076:12)
at Object.onceWrapper (node:events:485:28)
at IncomingMessage.emit (node:events:391:22)
at endReadableNT (node:internal/streams/readable:1307:12)
getPartyPowerError2 TypeError: Cannot read property 'split' of undefined
at Request._callback (C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js:86:61)
at Request.self.callback (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:185:22)
at Request.emit (node:events:379:20)
at Request. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1154:10)
at Request.emit (node:events:379:20)
at IncomingMessage. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1076:12)
at Object.onceWrapper (node:events:485:28)
at IncomingMessage.emit (node:events:391:22)
at endReadableNT (node:internal/streams/readable:1307:12)
at processTicksAndRejections (node:internal/process/task_queues:81:21)
Logged in as ꧁༺星夜༒紅茶༻᭄ꦿ࿐#1622!

傳送訊息時出現這個:

GetBaseExcelDataError TypeError: BaseExcelData.filter is not a function
at GetBaseExcelData (C:\Users\88690\OneDrive\桌面\dctsb\bot.js:831:31)
at BaseExcelFunction (C:\Users\88690\OneDrive\桌面\dctsb\bot.js:804:23)
at Client. (C:\Users\88690\OneDrive\桌面\dctsb\bot.js:90:17)
at Client.emit (node:events:379:20)
at MessageCreateAction.handle (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\actions\MessageCreate.js:31:14)
at Object.module.exports [as MESSAGE_CREATE] (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\websocket\handlers\MESSAGE_CREATE.js:4:32)
at WebSocketManager.handlePacket (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\websocket\WebSocketManager.js:384:31)
at WebSocketShard.onPacket (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\websocket\WebSocketShard.js:444:22)
at WebSocketShard.onMessage (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\websocket\WebSocketShard.js:301:10)
at WebSocket.onMessage (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\ws\lib\event-target.js:132:16)

微笑 iT邦研究生 5 級 ‧ 2021-02-04 16:39:33 檢舉

我這邊把你範例裡面的getBaseExcel改成這樣就可以了

//#region 傳送請求
exports.getBaseExcel = function(callback) {
    request(baseExcel, function(error, response) {
        try {
            if (error) {
                console.log('getBaseExcelError1', error);
                callback(false);
            } else {
                const data = JSON.parse(response.body); //接收回傳(response)的body
                callback(data);
            }
        } catch (err) {
            console.log('getBaseExcelError2', err);
            callback(false);
        }
    });
};

你的第一個報錯點在於get url抓到的資料應該是undefind
關於這點,你試試看在原本第36行的const data = JSON.parse(response.body);
前面加上console.log(response.body);

藉此觀察你抓到的資料是甚麼

另外我順便看了你的url,你的資料格式是這樣的

{
    "userID": 1,
    "userName": 20202914,
    "Joins": "Sam",
    "IsAdmin": "nothing"
  },

按照我的範例的話,我的是這樣

{
    "ID": 1,
    "DATE": 20200914,
    "NAME": "Sam",
    "VALUE": "nothing"
  },

因為使用的name不同,所以在bot.js底下的GetBaseExcelData方法也要改成以下

//BaseExcel字串比對
function GetBaseExcelData(msg) {
    try {
        if (BaseExcelData) {
            const userMessage = msg.content;

            e = BaseExcelData.filter(element => {
                return element.Joins === userMessage; //這邊改了
            })

            if (e.length != 0) return e[0].IsAdmin; //這邊改了
            else return false;
        }
    } catch (err) {
        console.log('GetBaseExcelDataError', err);
    }
}

你的UserPower跟PartyPower看起來還沒做,可以先註解掉、運行看看

具體來說是註解這些地方

bot.js

//#region 登入
client.login(auth.key);

client.on('ready', () => {
    GetGas.getBaseExcel(function(dataED) {
        if (dataED) {
            BaseExcelData = dataED //有資料
        }
        // GetGas.getUserPower(function(dataED) {
        //     if (dataED) {
        //         UserPowerData = dataED;
        //     }
        //     GetGas.getPartyPower(function(dataED) {
        //         if (dataED) {
        //             PartyPowerData = dataED;
        //         }
        console.log(`Logged in as ${client.user.tag}!`);
        //     });
        // })
    })
});

沒問題的話再繼續做就好,加油喔/images/emoticon/emoticon37.gif

可是我改好以後出現了這個:

}
.signin-card #Email {
margin-top: 16px;
}
.need-help {
float: right;
text-align: right;
}
.form-panel {
width: 274px;
}
#gaia_firstform {
z-index: 2;
}
.signin-card {
position: relative;
overflow: hidden;
}
.signin-card #profile-name {
color: #000;
}
.circle-mask {
display: block;
height: 96px;
width: 96px;
overflow: hidden;
border-radius: 50%;
margin-left: auto;
margin-right: auto;
z-index: 100;
margin-bottom: 10px;
}
.circle {
-webkit-transition-property: -webkit-transform;
-moz-transition-property: -moz-transform;
-ms-transition-property: -ms-transform;
-o-transition-property: -o-transform;
transition-property: transform;
-webkit-transition-timing-function: cubic-bezier(.645,.045,.355,1);
-moz-transition-timing-function: cubic-bezier(.645,.045,.355,1);
-ms-transition-timing-function: cubic-bezier(.645,.045,.355,1);
-o-transition-timing-function: cubic-bezier(.645,.045,.355,1);
transition-timing-function: cubic-bezier(.645,.045,.355,1);
}
.circle {
position: absolute;
z-index: 101;
height: 96px;
width: 96px;
border-radius: 50%;
opacity: 0.99;
overflow: hidden;
background-repeat: no-repeat;
background-position: center center;
}
.main {
overflow: hidden;
}
.card-mask-wrap {
position: relative;
width: 360px;
margin: 0 auto;
z-index: 1;
}
.dasher-tooltip {
position: absolute;
left: 50%;
margin-left: 150px;
}
.dasher-tooltip .tooltip-pointer {
margin-top: 15px;
}
.dasher-tooltip p {
margin-top: 0;
}
.dasher-tooltip p span {
display: block;
}
.card {
margin-bottom: 0;
}
.one-google {
padding-top: 27px;
}
#canvas {
-webkit-transition: opacity 0.075s;
-moz-transition: opacity 0.075s;
-ms-transition: opacity 0.075s;
-o-transition: opacity 0.075s;
transition: opacity 0.075s;
opacity: 0.01;
}
.shift-form #canvas {
opacity: 0.99;
}
.label {
color: #404040;
}
#account-chooser-link {
-webkit-transition: opacity 0.3s;
-moz-transition: opacity 0.3s;
-ms-transition: opacity 0.3s;
-o-transition: opacity 0.3s;
transition: opacity 0.3s;
}
.input-wrapper {
position: relative;
}
.google-footer-bar {
z-index: 2;
}

no-name

">

no-name">
<img class="circle-mask"

  src="https://ssl.gstatic.com/accounts/ui/avatar_2x.png"
>
                 placeholder="電子郵件地址或電話號碼"



               autofocus>
 no-name">
              selected="selected"
             >

‪繁體中文‬

      for (var key in params) {
        if (params.hasOwnProperty(key)) {
          var hiddenField = document.createElement('input');
          hiddenField.setAttribute('type', 'hidden');
          hiddenField.setAttribute('name', key);
          hiddenField.setAttribute('value', params[key]);

          form.appendChild(hiddenField);
        }
      }

      document.body.appendChild(form);
      form.submit();
    }
    var langChooser_getParamStr = function(params) {
      var paramsStr = [];
      for (var a in params) {
        paramsStr.push(a + "=" + params[a]);
      }
      return paramsStr.join('&');
    }
    var langChooser_currentUrl = window.location.href;
    var match = langChooser_currentUrl.match("^(.*?)(\\?(.*?))?(#(.*))?$");
    var langChooser_currentPath = match[1];
    var langChooser_params = langChooser_parseParams(match[3]);
    var langChooser_fragment = match[5];

    var langChooser = document.getElementById('lang-chooser');
    var langChooserWrap = document.getElementById('lang-chooser-wrap');
    var langVisControl = document.getElementById('lang-vis-control');
    if (langVisControl && langChooser) {
      langVisControl.style.display = 'inline';
      langChooser.onchange = function() {
        langChooser_params['lp'] = 1;
        langChooser_params['hl'] = encodeURIComponent(this.value);
        var hiddenEmailInput = document.getElementById('Email-hidden');
        if (hiddenEmailInput) {
          // If we are in password separation on password page, post to
          // /AccountLoginInfo.
          appendHiddenParams(langChooser_params);
          langChooser_params['Email'] = hiddenEmailInput.value;
          post('/AccountLoginInfo', langChooser_params);
        } else {
          var paramsStr = langChooser_getParamStr(langChooser_params);
          var newHref = langChooser_currentPath + "?" + paramsStr;
          if (langChooser_fragment) {
            newHref = newHref + "#" + langChooser_fragment;
          }
          window.location.href = newHref;
        }
      };
    }
  })();
</script>

getBaseExcelError2 SyntaxError: Unexpected token < in JSON at position 1
at JSON.parse ()
at Request._callback (C:\Users\88690\OneDrive\桌面\dctsb\Script\GetGas.js:36:62)
at Request.self.callback (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:185:22)
at Request.emit (node:events:379:20)
at Request. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1154:10)
at Request.emit (node:events:379:20)
at IncomingMessage. (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\request\request.js:1076:12)
at Object.onceWrapper (node:events:485:28)
at IncomingMessage.emit (node:events:391:22)
at endReadableNT (node:internal/streams/readable:1307:12)
Logged in as ꧁༺星夜༒紅茶༻᭄ꦿ࿐#1622!

微笑 iT邦研究生 5 級 ‧ 2021-02-04 18:40:54 檢舉

上面那串應該是貼錯吧..

你確認一下GetGas第36行是不是
const data = JSON.parse(response.body);

如果不是的話改一下,是或者改了還是有問題的話,在這行上面加上
console.log(response.body);
然後把log貼上來看看

如果url不是https://script.google.com/macros/s/AKfycbwH4y0em1fn8E7s9xUgn2k1kNrAIUEHzoiUZ8_w__28EeWzJj8LRwIYiA/exec
的話也貼上來

36行我改成這樣:

console.log(response.body);const data = JSON.parse(response.body); //接收回傳(response)的body

我的Auth.json是這樣:
{
"key": "ODA1MzgwMTg5NTMzMjQxMzc0.YBaCwA.Y-T2N12FXEI6cWmraNKOcMuRAag",
"Gas": {
"Get": [{
"baseExcel": "https://script.google.com/macros/s/AKfycbzSAOe1uDRKSi6Z5y170K_7W3QbogEMLpHcwe6Gh4q1qf0Fmb4X9tpH/exec",
"UserPower": "https://script.google.com/macros/s/AKfycbwH4y0em1fn8E7s9xUgn2k1kNrAIUEHzoiUZ8_w__28EeWzJj8LRwIYiA/exec",
"PartyPower": "https://script.googleusercontent.com/macros/echo?user_content_key=QSGaAiQUBOYrUSGC5fRTlflQYoMAJhrRTv6Id7cqaxSxyHelSQvvbVQIvTLWBjNOfwtXryJC6cz-DhAVasY2J_E7H0CJqubTm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnOSTL13mlbVHvRy-cnaOsslBJdJUu1rnVxAajZgGZBwAJc4qnPHI1rTE0HMf4PLKbl7j9UAldfGYvJsw0wqpxiI&lib=Mkoc1USkK2-hZ7oKXlAsdSh_vnidQkrZA"
}],
"Post": {
"UserPower": "https://script.google.com/macros/s/AKfycbwH4y0em1fn8E7s9xUgn2k1kNrAIUEHzoiUZ8_w__28EeWzJj8LRwIYiA/exec",
"PartyPower": "https://script.google.com/macros/s/AKfycbwH4y0em1fn8E7s9xUgn2k1kNrAIUEHzoiUZ8_w__28EeWzJj8LRwIYiA/exec"
}
}
}

Ps.Key已經更新過了

微笑 iT邦研究生 5 級 ‧ 2021-02-04 21:59:37 檢舉

你 baseExcel 的 url 好像不能訪問

那請問要怎麼處理?

微笑 iT邦研究生 5 級 ‧ 2021-02-04 22:19:35 檢舉

重看一次DAY20,改一下你的GAS,然後再發佈一次,得到可以正常訪問的URL

微笑 iT邦研究生 5 級 ‧ 2021-02-04 22:20:31 檢舉

或是直接改這個URL

https://script.google.com/macros/s/AKfycbwH4y0em1fn8E7s9xUgn2k1kNrAIUEHzoiUZ8_w__28EeWzJj8LRwIYiA/exec

這是你給我的,有可能你只是放錯資料。
用這套url會有其他問題,怎麼處理我上面有講

我修改好了,但出現這個:
PS C:\Users\88690\OneDrive\桌面\dctsb> node bot
[{"ID":"A1","type":2,"Power":"805381155314597890"}]
Logged in as ꧁༺星夜༒紅茶༻᭄ꦿ࿐#1622!

然後他就沒反應了

微笑 iT邦研究生 5 級 ‧ 2021-02-05 09:04:09 檢舉

[{"ID":"A1","type":2,"Power":"805381155314597890"}]

這個就是 console.log(response.body); 給的資料,也就是baseExcel的url
你是不是放錯資料了

你的

[
    {
        "ID": "A1",
        "type": 2,
        "Power": "805381155314597890"
    }
]

範例的

[
  {
    "ID": 1,
    "DATE": 20200914,
    "NAME": "Sam",
    "VALUE": "nothing"
  },
  {
    "ID": 2,
    "DATE": 20200814,
    "NAME": "Leo",
    "VALUE": "I'm Leo"
  },
  {
    "ID": 3,
    "DATE": 20200714,
    "NAME": "Alice",
    "VALUE": "I'm the bot"
  },
  {
    "ID": 4,
    "DATE": 20200614,
    "NAME": "Willy",
    "VALUE": "He's Willy"
  },
  {
    "ID": 5,
    "DATE": 20200514,
    "NAME": "Aaliayh",
    "VALUE": "呼呼呼"
  },
  {
    "ID": 6,
    "DATE": 20200414,
    "NAME": "Cara",
    "VALUE": "可拉可樂cccc"
  }
]

我用GAS抓表單,可是它都只抓到PartyPower的

微笑 iT邦研究生 5 級 ‧ 2021-02-05 16:28:19 檢舉

你每個excel跟gas獨立各一個檔案吧,不要混在一起
先把BaseExcel弄好再想PartyPower

獨立弄好了,再次啟動出現這個

PS C:\Users\88690\OneDrive\桌面\dctsb> node bot
[null,{"ID":1,"DATE":20202914,"NAME":"Sam","VALUE":"nothing"},{"ID":2,"DATE":20200814,"NAME":"Leo","VALUE":"I'm Leo"},{"ID":3,"DATE":20200714,"NAME":"Alice","VALUE":"I'm the bot"},{"ID":4,"DATE":20200614,"NAME":"Willy","VALUE":"He's Willy"},{"ID":5,"DATE":20200514,"NAME":"Aaliayh","VALUE":"
呼呼呼"},{"ID":6,"DATE":20200414,"NAME":"Cara","VALUE":"可拉可樂cccc"}]
Logged in as ꧁༺星夜༒紅茶༻᭄ꦿ࿐#1622!

還有doPost的網址一直有錯誤:
找不到以下指令碼函式:doGet

微笑 iT邦研究生 5 級 ‧ 2021-02-06 18:51:08 檢舉

console.log會顯示資料,那不是error
如果不想每次啟動都看到那堆資料的話,就把上次我請你加的console.log刪掉吧
你的第一個欄位是null有點尷尬,但應該沒問題...如果會catch的話你再把第一個null值拿掉吧,應該是塞陣列時從1開始塞了,要從0

doGet是googleAPI的默認Get方法
會跳這個訊息代表你寫成Get了
Post與Get的差別在於說,宣告標頭時Get是長這樣的

{
    'method':'Get',
    'url':'網址',
    'header':''
}

Post

{
    'method':'Post',
    'url':'網址',
    'header':'',
    form:{
        ...
    }
}

除了method要改成post以外,還要多加放置body參數的form
詳細的內容我推薦可以看這個

doPost的網址一直有錯誤,是在GAS建立的時候給的網址:
https://script.google.com/macros/s/AKfycbySHGPUy7J5hsxN6qIWbBNuEtoh4Zb1ERHuft5gN0VIxGGce9RoGE7c/exec

微笑 iT邦研究生 5 級 ‧ 2021-02-07 21:21:16 檢舉

post直接訪問是出不來的,一般我們點網址的行為是get
你想要模擬的話可以下載postman玩看看
我是建議先抄一份出來就好

我再次啟動傳訊息時出現這個:

PS C:\Users\88690\OneDrive\桌面\dctsb> node bot
Logged in as ꧁༺星夜༒紅茶༻᭄ꦿ࿐#1622!
GetBaseExcelDataError TypeError: Cannot read property 'Joins' of null
at C:\Users\88690\OneDrive\桌面\dctsb\bot.js:832:32
at Array.filter ()
at GetBaseExcelData (C:\Users\88690\OneDrive\桌面\dctsb\bot.js:831:31)
at BaseExcelFunction (C:\Users\88690\OneDrive\桌面\dctsb\bot.js:804:23)
at Client. (C:\Users\88690\OneDrive\桌面\dctsb\bot.js:90:17)
at Client.emit (node:events:379:20)
at MessageCreateAction.handle (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\actions\MessageCreate.js:31:14)
at Object.module.exports [as MESSAGE_CREATE] (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\websocket\handlers\MESSAGE_CREATE.js:4:32)
at WebSocketManager.handlePacket (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\websocket\WebSocketManager.js:384:31)
at WebSocketShard.onPacket (C:\Users\88690\OneDrive\桌面\dctsb\node_modules\discord.js\src\client\websocket\WebSocketShard.js:444:22)

微笑 iT邦研究生 5 級 ‧ 2021-02-08 17:38:51 檢舉
//BaseExcel字串比對
function GetBaseExcelData(msg) {
    try {
        if (BaseExcelData) {
            const userMessage = msg.content;

            e = BaseExcelData.filter(element => {
                return element.Joins === userMessage; //這邊改了
            })

            if (e.length != 0) return e[0].IsAdmin; //這邊改了
            else return false;
        }
    } catch (err) {
        console.log('GetBaseExcelDataError', err);
    }
}

你上次有改這段吧,我是依照你給的url去改的
你看一下我上面有說為什麼要改這兩段,然後再看看自己的url參數叫甚麼,就知道怎麼改了

我要留言

立即登入留言